package com.yf.exam.modules.user.cert.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yf.exam.core.api.dto.PagingReqDTO;
import com.yf.exam.modules.cert.entity.Cert;
import com.yf.exam.modules.cert.service.CertService;
import com.yf.exam.modules.exam.entity.Exam;
import com.yf.exam.modules.exam.mapper.ExamMapper;
import com.yf.exam.modules.paper.entity.Paper;
import com.yf.exam.modules.paper.service.PaperService;
import com.yf.exam.modules.sys.user.dto.SysUserDTO;
import com.yf.exam.modules.sys.user.entity.SysUser;
import com.yf.exam.modules.sys.user.service.SysUserService;
import com.yf.exam.modules.user.cert.dto.UserCertDetailDTO;
import com.yf.exam.modules.user.cert.dto.request.UserCertReqDTO;
import com.yf.exam.modules.user.cert.entity.UserCert;
import com.yf.exam.modules.user.cert.mapper.UserCertMapper;
import com.yf.exam.modules.user.cert.service.UserCertService;
import com.yf.exam.modules.user.cert.utils.CertGenerateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import org.springframework.beans.factory.annotation.Qualifier;
import java.io.File;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;

/**
 * 用户证书服务实现类
 */
@Slf4j
@Service
public class UserCertServiceImpl extends ServiceImpl<UserCertMapper, UserCert> implements UserCertService {
    
    // 注入证书生成专用线程池
    @Autowired
    @Qualifier("certGenerateExecutor")
    private Executor certGenerateExecutor;
    
    @Autowired
    private CertService certService;

    @Autowired
    private ExamMapper examMapper;

    @Autowired
    private UserCertMapper userCertMapper;

    @Autowired
    private PaperService paperService;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private CertGenerateUtils certGenerateUtils;


    @Override
    @Transactional
    public void generateCertificatesForPassedUsers(String examId) {
        log.info("开始为考试ID:{}生成证书", examId);
        
        // 获取通过考试的试卷记录
        List<Paper> passedPapers = getPassedPapers(examId);
        if (passedPapers.isEmpty()) {
            return;
        }

        // 批量生成证书
        generateCertificatesForPapers(passedPapers, examId);
    }

    @Override
    public void generateCertificateForUser(String userId, String examId, String paperId) {
        log.info("开始为用户ID:{}在考试ID:{}中生成证书", userId, examId);
        
        // 构造单个用户的试卷列表，复用批量生成逻辑
        Paper paper = new Paper();
        paper.setUserId(userId);
        paper.setExamId(examId);
        paper.setId(paperId);
        
        List<Paper> singlePaperList = Arrays.asList(paper);
        generateCertificatesForPapers(singlePaperList, examId);
    }
    
    /**
     * 统一的批量证书生成方法
     * @param papers 试卷列表
     * @param examId 考试ID
     */
    private void generateCertificatesForPapers(List<Paper> papers, String examId) {
        // 获取考试关联的证书模板ID
        String certId = getExamCertTemplateId(examId);
        if (certId == null) {
            return;
        }
        
        int submittedCount = 0;
        for (Paper paper : papers) {
            try {
                // 检查是否可以生成证书
                if (!canGenerateCertificate(paper.getUserId(), examId, certId)) {
                    continue;
                }
                
                // 直接异步生成证书（简化调用链）
                generateCertificateAsync(paper.getUserId(), examId, certId, paper.getId());
                submittedCount++;
            } catch (Exception e) {
                log.error("提交证书生成任务失败: userId={}, examId={}", paper.getUserId(), examId, e);
            }
        }
        
        log.info("已为考试ID:{}提交{}个证书生成任务到线程池", examId, submittedCount);
    }


    
    /**
     * 执行证书生成的核心逻辑（简化后的版本）
     */
    private String doGenerateCertificate(String userId, String examId, String certId, String paperId) {
        // 更新状态为生成中
        saveOrUpdateUserCert(userId, examId, certId, paperId, null, UserCert.STATUS_GENERATING);
        
        try {
            // 生成证书
            String certUrl = generateSingleCertificate(userId, examId, certId);
            
            // 保存生成成功状态
            saveOrUpdateUserCert(userId, examId, certId, paperId, certUrl, UserCert.STATUS_GENERATED);
            
            log.info("证书生成成功: userId={}, examId={}, certId={}, certUrl={}", userId, examId, certId, certUrl);
            return certUrl;
        } catch (Exception e) {
            // 保存生成失败状态
            saveOrUpdateUserCert(userId, examId, certId, paperId, null, UserCert.STATUS_FAILED);
            log.error("证书生成失败: userId={}, examId={}, certId={}", userId, examId, certId, e);
            throw e;
        }
    }
    


    @Override
    @Transactional
    public String manualGenerateCertificate(String userId, String examId, String certId) {
        log.info("开始手动生成证书: userId={}, examId={}, certId={}", userId, examId, certId);
        
        try {
            // 检查是否可以生成证书
            if (!canGenerateCertificate(userId, examId, certId)) {
                UserCert existingCert = getUserCert(userId, examId, certId);
                return existingCert != null ? existingCert.getCertUrl() : null;
            }
            
            // 获取用户的试卷ID
            String paperId = getUserPaperId(userId, examId);
            
            // 直接调用核心生成逻辑（简化调用链）
            return doGenerateCertificate(userId, examId, certId, paperId);
        } catch (Exception e) {
            log.error("手动生成证书失败: userId={}, examId={}, certId={}", userId, examId, certId, e);
            throw e;
        }
    }

    @Override
    public IPage<UserCertDetailDTO> getUserCertDetailPage(PagingReqDTO<UserCertReqDTO> reqDTO) {
        Page<UserCertDetailDTO> page = new Page<>(reqDTO.getCurrent(), reqDTO.getSize());
        return userCertMapper.selectUserCertDetailPage(page, reqDTO.getParams());
    }

    @Override
    public List<UserCertDetailDTO> getUserCertDetailList(String userId, String examId) {
        return userCertMapper.selectUserCertDetailList(userId, examId);
    }

    @Override
    @Transactional
    public boolean deleteUserCertificate(String userId, String examId, String certId) {
        log.info("开始删除用户证书: userId={}, examId={}, certId={}", userId, examId, certId);
        
        try {
            // 获取用户证书记录
            UserCert userCert = getUserCert(userId, examId, certId);
            if (userCert == null) {
                log.warn("用户证书不存在: userId={}, examId={}, certId={}", userId, examId, certId);
                return false;
            }
            
            // 删除物理文件
            if (userCert.getCertUrl() != null && !userCert.getCertUrl().isEmpty()) {
                int fileDeleteResult = deletePhysicalFile(userCert.getCertUrl());
                if (fileDeleteResult == 1) {
                    log.info("物理文件删除成功: userId={}, examId={}, certId={}", userId, examId, certId);
                } else if (fileDeleteResult == 0) {
                    log.warn("物理文件不存在: userId={}, examId={}, certId={}", userId, examId, certId);
                } else {
                    log.warn("物理文件删除失败: userId={}, examId={}, certId={}", userId, examId, certId);
                }
            }
            
            // 删除数据库记录
            boolean result = removeById(userCert.getId());
            
            if (result) {
                log.info("用户证书删除成功: userId={}, examId={}, certId={}", userId, examId, certId);
            } else {
                log.error("用户证书删除失败: userId={}, examId={}, certId={}", userId, examId, certId);
            }
            
            return result;
        } catch (Exception e) {
            log.error("删除用户证书时发生异常: userId={}, examId={}, certId={}", userId, examId, certId, e);
            throw e;
        }
    }

    @Override
    @Transactional
    public int deleteAllCertificatesByExam(String examId) {
        log.info("开始批量删除考试证书: examId={}", examId);
        
        try {
            // 查询该考试的所有证书记录
            QueryWrapper<UserCert> wrapper = new QueryWrapper<>();
            wrapper.eq("exam_id", examId);
            List<UserCert> userCerts = list(wrapper);
            
            if (userCerts.isEmpty()) {
                log.info("考试ID:{}没有证书记录，无需删除", examId);
                return 0;
            }
            
            int totalCount = userCerts.size();
            int dbDeletedCount = 0;
            int fileDeletedCount = 0;
            int fileNotExistCount = 0;
            int fileDeleteFailedCount = 0;
            
            // 删除物理文件和数据库记录
            for (UserCert userCert : userCerts) {
                try {
                    // 删除物理文件
                    if (userCert.getCertUrl() != null && !userCert.getCertUrl().isEmpty()) {
                        int fileDeleteResult = deletePhysicalFile(userCert.getCertUrl());
                        if (fileDeleteResult == 1) {
                            fileDeletedCount++;
                        } else if (fileDeleteResult == 0) {
                            fileNotExistCount++;
                        } else {
                            fileDeleteFailedCount++;
                        }
                    } else {
                        fileNotExistCount++; // 没有文件路径也算作文件不存在
                    }
                    
                    // 删除数据库记录
                    if (removeById(userCert.getId())) {
                        dbDeletedCount++;
                    }
                } catch (Exception e) {
                    log.error("删除单个证书失败: userCertId={}, userId={}, examId={}", 
                            userCert.getId(), userCert.getUserId(), examId, e);
                    fileDeleteFailedCount++;
                    // 继续处理其他证书，不中断整个批量删除过程
                }
            }
            
            log.info("批量删除考试证书完成: examId={}, 总数={}, 数据库删除={}, 文件删除成功={}, 文件不存在={}, 文件删除失败={}", 
                    examId, totalCount, dbDeletedCount, fileDeletedCount, fileNotExistCount, fileDeleteFailedCount);
            return dbDeletedCount;
        } catch (Exception e) {
            log.error("批量删除考试证书时发生异常: examId={}", examId, e);
            throw e;
        }
    }

    /**
     * 生成单个证书
     */
    private String generateSingleCertificate(String userId, String examId, String certId) {
        // 获取用户信息
        SysUser user = sysUserService.getById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在: " + userId);
        }
        
        SysUserDTO userDTO = new SysUserDTO();
        BeanUtils.copyProperties(user, userDTO);
        
        // 获取证书模板信息
        Cert cert = certService.getById(certId);
        if (cert == null) {
            throw new RuntimeException("证书模板不存在: " + certId);
        }
        
        // 生成证书
        return certGenerateUtils.generateCertificate(cert, userDTO);
    }


    
    // ==================== 提取的公共方法 ====================
    
    /**
     * 获取考试关联的证书模板ID
     */
    private String getExamCertTemplateId(String examId) {
        Exam exam = examMapper.selectById(examId);
        if (exam != null && exam.getCertId() != null) {
            log.info("考试ID:{}关联的证书模板ID:{}", examId, exam.getCertId());
            return exam.getCertId();
        } else {
            log.info("考试 {} 未关联证书模板，跳过证书生成", examId);
            return null;
        }
    }
    
    /**
     * 获取通过考试的试卷记录
     */
    private List<Paper> getPassedPapers(String examId) {
        List<Paper> passedPapers = getPapers(examId, null, 2, true);
        log.info("考试ID:{}通过考试的用户数量:{}", examId, passedPapers.size());
        
        // 添加详细的调试信息
        if (passedPapers.isEmpty()) {
            // 查询该考试的所有试卷记录进行诊断
            List<Paper> allPapers = getPapers(examId, null, null, null);
            log.info("考试ID:{}的所有试卷记录数量:{}", examId, allPapers.size());
            
            for (Paper paper : allPapers) {
                log.info("试卷详情 - ID:{}, 用户ID:{}, 状态:{}, 用户得分:{}, 及格分:{}, 是否通过:{}", 
                        paper.getId(), paper.getUserId(), paper.getState(), 
                        paper.getUserScore(), paper.getQualifyScore(), 
                        paper.getUserScore() != null && paper.getQualifyScore() != null && paper.getUserScore() >= paper.getQualifyScore());
            }
            log.info("考试ID:{}没有通过考试的用户，跳过证书生成", examId);
        }
        
        return passedPapers;
    }
    
    /**
     * 检查是否可以生成证书（合并状态检查逻辑）
     */
    private boolean canGenerateCertificate(String userId, String examId, String certId) {
        UserCert existingCert = getUserCert(userId, examId, certId);
        if (existingCert == null) {
            return true;
        }
        
        int status = existingCert.getStatus();
        if (status == UserCert.STATUS_GENERATED) {
            log.info("用户 {} 在考试 {} 的证书已存在，跳过生成", userId, examId);
            return false;
        }
        if (status == UserCert.STATUS_GENERATING) {
            log.warn("用户 {} 在考试 {} 的证书正在生成中，跳过重复请求", userId, examId);
            return false;
        }
        return true;
    }
    

    
    /**
     * 异步生成证书的便捷方法
     */
    private void generateCertificateAsync(String userId, String examId, String certId, String paperId) {
        CompletableFuture.runAsync(() -> {
            try {
                doGenerateCertificate(userId, examId, certId, paperId);
            } catch (Exception e) {
                log.error("异步证书生成失败: userId={}, examId={}, certId={}", userId, examId, certId, e);
            }
        }, certGenerateExecutor);
    }
    
    /**
     * 通用的试卷查询方法
     */
    private List<Paper> getPapers(String examId, String userId, Integer state, Boolean passed) {
        QueryWrapper<Paper> wrapper = new QueryWrapper<>();
        wrapper.eq("exam_id", examId);
        
        if (userId != null) wrapper.eq("user_id", userId);
        if (state != null) wrapper.eq("state", state);
        if (passed != null && passed) wrapper.apply("user_score >= qualify_score");
        
        return paperService.list(wrapper);
    }
    
    /**
     * 获取用户的试卷ID
     */
    private String getUserPaperId(String userId, String examId) {
        List<Paper> papers = getPapers(examId, userId, 2, null);
        return papers.isEmpty() ? null : papers.get(0).getId();
    }
    
    /**
     * 获取用户证书记录
     */
    private UserCert getUserCert(String userId, String examId, String certId) {
        QueryWrapper<UserCert> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId)
               .eq("exam_id", examId)
               .eq("id", certId);
        return getOne(wrapper);
    }
    
    /**
     * 保存或更新用户证书记录
     */
    private void saveOrUpdateUserCert(String userId, String examId, String certId, String paperId, String certUrl, int status) {
        UserCert userCert = getUserCert(userId, examId, certId);
        
        if (userCert == null) {
            userCert = new UserCert();
            userCert.setUserId(userId);
            userCert.setExamId(examId);
            userCert.setCertId(certId);
            userCert.setPaperId(paperId);
            userCert.setCreateTime(new Date());
        }
        
        userCert.setCertUrl(certUrl);
        userCert.setStatus(status);
        userCert.setUpdateTime(new Date());
        
        if (status == UserCert.STATUS_GENERATED) {
            userCert.setGenerateTime(new Date());
        }
        
        saveOrUpdate(userCert);
    }
    
    /**
     * 删除物理文件
     * @param fileUrl 文件URL或路径
     * @return 删除结果：0-文件不存在，1-删除成功，-1-删除失败
     */
    private int deletePhysicalFile(String fileUrl) {
        try {
            if (fileUrl == null || fileUrl.isEmpty()) {
                return 0;
            }
            
            // 标准化文件路径
            String filePath = normalizeFilePath(fileUrl);
            
            File file = new File(filePath);
            if (!file.exists()) {
                log.warn("物理文件不存在: {}", filePath);
                return 0;
            }
            
            if (!file.isFile()) {
                log.warn("路径不是文件: {}", filePath);
                return 0;
            }
            
            boolean deleted = file.delete();
            if (deleted) {
                log.info("物理文件删除成功: {}", filePath);
                return 1;
            } else {
                log.warn("物理文件删除失败: {}", filePath);
                return -1;
            }
        } catch (Exception e) {
            log.error("删除物理文件时发生异常: fileUrl={}", fileUrl, e);
            return -1;
        }
    }
    
    /**
     * 标准化文件路径，处理Windows和Linux路径分隔符
     * @param fileUrl 原始文件URL或路径
     * @return 标准化后的文件路径
     */
    private String normalizeFilePath(String fileUrl) {
        String filePath = fileUrl;
        
        // 如果是URL格式，提取文件路径部分
        if (filePath.startsWith("http")) {
            int uploadIndex = filePath.indexOf("/upload/");
            if (uploadIndex != -1) {
                filePath = filePath.substring(uploadIndex + 1);
                // 处理URL中的 /upload/file/certs/ 映射到实际的 upload/certs/ 路径
                if (filePath.startsWith("upload/file/certs/")) {
                    filePath = filePath.replace("upload/file/certs/", "upload/certs/");
                }
            }
        }
        
        // 统一使用系统文件分隔符
        filePath = filePath.replace('/', File.separatorChar).replace('\\', File.separatorChar);
        
        // 如果是相对路径，转换为绝对路径
        if (!filePath.startsWith(File.separator) && !filePath.contains(":")) {
            filePath = System.getProperty("user.dir") + File.separator + filePath;
        }
        
        return filePath;
    }
}